package com.hmdp.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmdp.dto.Result;
import com.hmdp.entity.RedisData;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisConstants;
import com.hmdp.utils.RedisUtils;
import com.hmdp.utils.SystemConstants;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Circle;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@Slf4j
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisUtils redisUtils;
    @Override
    public Result queryById(Long id) {
        Shop shop = redisUtils.cacheRebuild(id, RedisConstants.CACHE_SHOP_KEY,
                RedisConstants.LOCK_SHOP_KEY, RedisConstants.CACHE_SHOP_TTL
                ,TimeUnit.SECONDS,Shop.class, this::getById);
        return Result.ok(shop);
    }

    @Override
    public void updateShop(Shop shop) {
        if(shop.getId()==null){
            return;
        }
        updateById(shop);
        stringRedisTemplate.delete("cache:shop:" + shop.getId());
    }

    @Override
    public void saveWithExpired(Shop shop) {
        save(shop);
        String key = RedisConstants.CACHE_SHOP_KEY + shop.getId();
        RedisData<Shop> redisData = new RedisData(LocalDateTime.now().plusSeconds(RedisConstants.CACHE_SHOP_TTL),shop);
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
    }

    @Override
    public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
        // 如果没有坐标参数，执行普通分页查询
        if (x == null || y == null) {
            Page<Shop> page = query()
                    .eq("type_id", typeId)
                    .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
            return Result.ok(page.getRecords());
        }

        // 计算分页范围
        int pageSize = SystemConstants.MAX_PAGE_SIZE;
        int offset = (current - 1) * pageSize;

        // 构建Redis GEO查询（使用GEORADIUS）
        String key = RedisConstants.SHOP_GEO_KEY + typeId;
        double radius = 5000; // 5公里半径（单位：米）

        GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo()
                .radius(
                        key,
                        new Circle(new Point(x, y), radius),
                        RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                                .includeDistance()
                                .sortAscending()  // 按距离升序排序
                                .limit(offset + pageSize) // 获取到当前页结束的所有数据
                );

        if (results == null || results.getContent().isEmpty()) {
            return Result.ok(Collections.emptyList());
        }

        // 处理分页
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = results.getContent();
        if (content.size() <= offset) {
            return Result.ok(Collections.emptyList()); // 没有足够的数据填充当前页
        }

        // 提取当前页的数据
        List<Long> ids = new ArrayList<>(pageSize);
        List<Double> distances = new ArrayList<>(pageSize);

        content.stream()
                .skip(offset)
                .limit(pageSize)
                .forEach(geoResult -> {
                    distances.add(geoResult.getDistance().getValue());
                    ids.add(Long.valueOf(geoResult.getContent().getName()));
                });

        // 查询店铺详情
        List<Shop> shops = query().in("id", ids).list();

        // 保持原始顺序并设置距离
        Map<Long, Shop> shopMap = shops.stream()
                .collect(Collectors.toMap(Shop::getId, Function.identity()));

        List<Shop> orderedShops = new ArrayList<>(pageSize);
        for (Long id : ids) {
            Shop shop = shopMap.get(id);
            if (shop != null) {
                shop.setDistance(distances.get(ids.indexOf(id)));
                orderedShops.add(shop);
            }
        }

        return Result.ok(orderedShops);
    }
}